PHP新手30天實戰金流, Laravel6參考此平台架構概觀, 測試範例試跑
一個購物平台主要的三個 Model:
產生兩張 table (products, product_skus) 來管理。
Product :
Schema::create('products', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->text('description');
        $table->string('image');
        $table->boolean('on_sale')->default(true);
        $table->float('rating')->default(5);
        $table->unsignedInteger('sold_count')->default(0);
        $table->unsignedInteger('review_count')->default(0);
        $table->decimal('price', 10, 2);
        $table->timestamps();
    });
public function skus()
{
    return $this->hasMany(ProductSku::class);
}
ProductSku : Stock Keeping Unit,簡稱SKU,定義為保存庫存控制的最小可用單位
Schema::create('product_skus', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->string('description');
        $table->decimal('price', 10, 2);
        $table->unsignedInteger('stock');
        $table->unsignedInteger('product_id');
        $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
        $table->timestamps();
    });
 
ProductSkuAttribute : 商品屬性-規格大小顏色
Schema::create('product_sku_attributes', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->text('items');
            $table->unsignedInteger('product_id');
            $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
            $table->timestamps();
        });
 
產生兩張 table (orders, order_iterms) 來管理。
Order : 沒有任何商品資訊
Schema::create('orders', function (Blueprint $table) {
        $table->increments('id');
        $table->string('no')->unique();
        $table->unsignedInteger('user_id');
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->text('address');
        $table->decimal('total_amount', 10, 2);
        $table->text('remark')->nullable();
        $table->dateTime('paid_at')->nullable();
        $table->string('payment_method')->nullable();
        $table->string('payment_no')->nullable();
        $table->string('refund_status')->default(\App\Models\Order::REFUND_STATUS_PENDING);
        $table->string('refund_no')->unique()->nullable();
        $table->boolean('closed')->default(false);
        $table->boolean('reviewed')->default(false);
        $table->string('ship_status')->default(\App\Models\Order::SHIP_STATUS_PENDING);
        $table->text('ship_data')->nullable();
        $table->text('extra')->nullable();
        $table->timestamps();
    });
OrderItem:
Schema::create('order_items', function (Blueprint $table) {
        $table->increments('id');
        $table->unsignedInteger('order_id');
        $table->foreign('order_id')->references('id')->on('orders')->onDelete('cascade');
        $table->unsignedInteger('product_id');
        $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
        $table->unsignedInteger('product_sku_id');
        $table->foreign('product_sku_id')->references('id')->on('product_skus')->onDelete('cascade');
        $table->unsignedInteger('amount');
        $table->decimal('price', 10, 2);
        $table->unsignedInteger('rating')->nullable();
        $table->text('review')->nullable();
        $table->timestamp('reviewed_at')->nullable();
    });
cart_items:Schema::create('cart_items', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('user_id');
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->unsignedInteger('product_sku_id');
            $table->foreign('product_sku_id')->references('id')->on('product_skus')->onDelete('cascade');
            $table->unsignedInteger('amount');
        });
User
Product
@foreach($product->attrs as $attr_index => $attr)
Product_sku
-- 好像沒有用到的函式 getAttrsAttribute --
public function getAttrsAttribute()
{
    $attrs = $this->product->attrs;
    $attr_items_index = json_decode($this->attr_items_index, true);
    return collect($attr_items_index)->mapWithKeys(function ($item_index, $index) use ($attrs) {
        $attr = $attrs->get($index);
        return [$attr->name => $attr->items[$item_index]];
    });
}
function ($item_index, $index) use ($attrs) {
        $attr = $attrs->get($index);
        return [$attr->name => $attr->items[$item_index]];
    }
Order
public function user()
{
    return $this->belongsTo(User::class);
}
protected static function boot()
{
    parent::boot();
    // 監聽模型建立事件,在寫入 DB之前觸發
    static::creating(function ($model) {
        // 如果模型的 no 字段为空
        if (!$model->no) {
            // 調用 findAvailableNo 生成訂單流水號
            $model->no = static::findAvailableNo();
            // 如果失敗,則终止建立訂單
            if (!$model->no) {
                return false;
            }
        }
    });
}
OrderItem
CartItem
將資料在 DB 儲存的型態轉換成一般較通用的型態,方便操作。
Cart
Orders
public function store(OrderRequest $request, OrderService $orderService)
    {
        $user = $request->user();
        $address = UserAddress::find($request->input('address_id'));
        $currency_code="THB";
        return $orderService->store($user, $address, $request->input('remark'), $request->input('items'),$currency_code);
    }
猜...處理資料庫事務程式碼太多, 不宜放在高層
Payment
Products
index
show
favor
disfavor
favorites
show product 會去撈出該商品的27種規格的庫存:
$skus = $product->skus->map(function ($sku) {
return [
    'id' => $sku->id,
    'price' => $sku->price,
    'stock' => $sku->stock,
    'attr_items_index' => json_decode($sku->attr_items_index, true),
];
});
dd($skus);
 
php test.php
會回傳測試用的付款畫面